﻿using System;
using System.Collections.Generic;
using mqtttLib.Helper;

namespace mqtttLib.Messages.Base
{
    /// <summary>
    /// 固定头
    /// </summary>
    public class FixedHeader
    {
        /// <summary>
        ///消息类型
        /// </summary>
        public MessageType MessageType { get; set; }
        /// <summary>
        /// DUP   重发标志 表示这是客户端或服务端第一次请求发送这个PUBLISH报文。如果DUP标志被设置为1，表示这可能是一个早前报文请求的重发。
        /// </summary>
        public bool Dup { get; set; }
        /// <summary>
        /// QoS  服务质量
        /// </summary>
        public Qos Qos { get; set; }
        /// <summary>
        /// RETAIN 保持
        /// </summary>
        public bool Retain { get; set; }
        /// <summary>
        /// 剩余长度(消息长度)
        /// </summary>
        public int RemaingLength { get; set; }

        public FixedHeader(MessageType msgType)
        {
            MessageType = msgType;
        }
 
        public FixedHeader(byte[] buffer)
        {
            if (buffer.Length < 2)
                throw new Exception("所提供的报头无效,至少长2字节");

            var byte1 = buffer[0];
            MessageType = (MessageType)((byte1 & 0xf0) >> 4);
            Dup = ((byte1 & 0x08) >> 3) > 0;
            Qos = (Qos)((byte1 & 0x06) >> 1);
            Retain = (byte1 & 0x01) > 0;
            RemaingLength = GetDataObjectLenght(buffer);
        }
        public byte[] GetDataBytes()
        {
            var result = new List<byte>();
            var flags = (byte)MessageType << 4;
            flags |= Dup.ToByte() << 3;
            flags |= (byte)Qos << 1;
            flags |= Retain.ToByte();
            result.Add((byte)flags);

            byte[] temp = EncodeLength(RemaingLength);
            result.AddRange(temp);
            return result.ToArray();
        }
        /// <summary>
        /// 编码长度
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private static byte[] EncodeLength(int length)
        {
            var result = new List<byte>();
            do
            {
                var digit = (byte)(length % 0x80);
                length /= 0x80;
                if (length > 0)
                    digit |= 0x80;
                result.Add(digit);
            } while (length > 0);

            return result.ToArray();
        }
        /// <summary>
        /// 解析 长度
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private static int GetDataObjectLenght(byte[] buffer)
        {
            byte encodedByte;
            var multiplier = 1;
            var remainingLength = 0;
            int i = 1;
            do
            {
                encodedByte = buffer[i++];
                remainingLength += (encodedByte & 0x7f) * multiplier;
                multiplier *= 0x80;
            } while ((encodedByte & 0x80) != 0);

            return remainingLength;
        } 
    }
}
